home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / udp.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  7KB  |  311 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "internet.h"
  7.  
  8. /* Hash table for UDP structures */
  9. struct udp_cb *udps[NUDP] = { NULLUDP} ;
  10. struct udp_stat udp_stat;    /* Statistics */
  11.  
  12. /* Create a UDP control block for lsocket, so that we can queue
  13.  * incoming datagrams.
  14.  */
  15. int
  16. open_udp(lsocket,r_upcall)
  17. struct socket *lsocket;
  18. void (*r_upcall)();
  19. {
  20.     register struct udp_cb *up;
  21.     struct udp_cb *lookup_udp();
  22.     int16 hval,hash_udp();
  23.  
  24.     if((up = lookup_udp(lsocket)) != NULLUDP)
  25.         return 0;    /* Already exists */
  26.     if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
  27.         net_error = NO_SPACE;
  28.         return -1;
  29.     }
  30.     up->rcvq = NULLBUF;
  31.     up->rcvcnt = 0;
  32.     up->socket.address = lsocket->address;
  33.     up->socket.port = lsocket->port;
  34.     up->r_upcall = r_upcall;
  35.  
  36.     hval = hash_udp(lsocket);
  37.     up->next = udps[hval];
  38.     up->prev = NULLUDP;
  39.     if(up->next != NULLUDP)
  40.         up->next->prev = up;
  41.     udps[hval] = up;
  42.     return 0;
  43. }
  44.  
  45. /* Send a UDP datagram */
  46. int
  47. send_udp(lsocket,fsocket,tos,ttl,data,length,id,df)
  48. struct socket *lsocket;        /* Source socket */
  49. struct socket *fsocket;        /* Destination socket */
  50. char tos;            /* Type-of-service for IP */
  51. char ttl;            /* Time-to-live for IP */
  52. struct mbuf *data;        /* Data field, if any */
  53. int16 length;            /* Length of data field */
  54. int16 id;            /* Optional ID field for IP */
  55. char df;            /* Don't Fragment flag for IP */
  56. {
  57.     struct mbuf *htonudp(),*bp;
  58.     struct pseudo_header ph;
  59.     struct udp udp;
  60.  
  61.     length = UDPHDR;
  62.     if(data != NULLBUF)
  63.         length += len_mbuf(data);
  64.  
  65.     udp.source = lsocket->port;
  66.     udp.dest = fsocket->port;
  67.     udp.length = length;
  68.  
  69.     /* Create IP pseudo-header, compute checksum and send it */
  70.     ph.length = length;
  71.     ph.source = lsocket->address;
  72.     ph.dest = fsocket->address;
  73.     ph.protocol = UDP_PTCL;
  74.  
  75.     if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  76.         net_error = NO_SPACE;
  77.         free_p(data);
  78.         return 0;
  79.     }
  80.     udp_stat.sent++;
  81.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  82.     return length;
  83. }
  84.  
  85. /* Accept a waiting datagram, if available. Returns length of datagram */
  86. int
  87. recv_udp(lsocket,fsocket,bp)
  88. struct socket *lsocket;        /* Local socket to receive on */
  89. struct socket *fsocket;        /* Place to stash incoming socket */
  90. struct mbuf **bp;            /* Place to stash data packet */
  91. {
  92.     struct udp_cb *lookup_udp();
  93.     register struct udp_cb *up;
  94.     struct socket *sp;
  95.     struct mbuf *buf;
  96.     int16 length;
  97.  
  98.     up = lookup_udp(lsocket);
  99.     if(up == NULLUDP){
  100.         net_error = NO_CONN;
  101.         return -1;
  102.     }
  103.     if(up->rcvcnt == 0){
  104.         net_error = WOULDBLK;
  105.         return -1;
  106.     }
  107.     buf = dequeue(&up->rcvq);
  108.     up->rcvcnt--;
  109.  
  110.     sp = (struct socket *)buf->data;
  111.     /* Fill in the user's foreign socket structure, if given */
  112.     if(fsocket != NULLSOCK){
  113.         fsocket->address = sp->address;
  114.         fsocket->port = sp->port;
  115.     }
  116.     /* Strip socket header and hand data to user */
  117.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  118.     length = len_mbuf(buf);
  119.     if(bp != (struct mbuf **)NULL)
  120.         *bp = buf;
  121.     else
  122.         free_p(buf);
  123.     return length;
  124. }
  125. /* Delete a UDP control block */
  126. int
  127. del_udp(lsocket)
  128. struct socket *lsocket;
  129. {
  130.     register struct udp_cb *up;
  131.     struct udp_cb *lookup_udp();
  132.     struct mbuf *bp;
  133.     int16 hval,hash_udp();
  134.  
  135.     if((up = lookup_udp(lsocket)) == NULLUDP){
  136.         net_error = INVALID;
  137.         return -1;
  138.     }        
  139.     /* Get rid of any pending packets */
  140.     while(up->rcvcnt != 0){
  141.         bp = up->rcvq;
  142.         up->rcvq = up->rcvq->anext;
  143.         free_p(bp);
  144.         up->rcvcnt--;
  145.     }
  146.     hval = hash_udp(&up->socket);
  147.     if(udps[hval] == up){
  148.         /* First on list */
  149.         udps[hval] = up->next;
  150.         if (up->next != NULLUDP)
  151.             up->next->prev = NULLUDP;
  152.     } else {
  153.         up->prev->next = up->next;
  154.         if (up->next != NULLUDP)
  155.             up->next->prev = up->prev;
  156.     }
  157.     free((char *)up);
  158.     return 0;
  159. }
  160. /* Process an incoming UDP datagram */
  161. /*ARGSUSED*/
  162. void
  163. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  164. struct mbuf *bp;    /* UDP header and data */
  165. char protocol;        /* Should always be 17 */
  166. int32 source;        /* Source IP address */
  167. int32 dest;        /* Dest IP address */
  168. char tos;
  169. int16 length;
  170. char rxbroadcast;    /* The only protocol that accepts 'em */
  171. {
  172.     struct pseudo_header ph;
  173.     struct udp udp;
  174.     struct udp_cb *up,*lookup_udp();
  175.     struct socket lsocket;
  176.     struct socket *fsocket;
  177.     struct mbuf *packet;
  178.     int ckfail = 0;
  179.  
  180.     if(bp == NULLBUF)
  181.         return;
  182.  
  183.     udp_stat.rcvd++;
  184.  
  185.     /* Create pseudo-header and verify checksum */
  186.     ph.source = source;
  187.     ph.dest = dest;
  188.     ph.protocol = protocol;
  189.     ph.length = length;
  190.  
  191.     if(cksum(&ph,bp,length) != 0)
  192.         /* Checksum apparently failed, note for later */
  193.         ckfail++;
  194.  
  195.     /* Extract UDP header in host order */
  196.     ntohudp(&udp,&bp);
  197.  
  198.     /* If the checksum field is zero, then ignore a checksum error.
  199.      * I think this is dangerously wrong, but it is in the spec.
  200.      */
  201.     if(ckfail && udp.checksum != 0){
  202.         udp_stat.cksum++;
  203.         free_p(bp);
  204.         return;
  205.     }
  206.     /* If this was a broadcast packet, pretend it was sent to us */
  207.     if(rxbroadcast){
  208.         lsocket.address = ip_addr;
  209.         udp_stat.bdcsts++;
  210.     } else
  211.         lsocket.address = dest;
  212.  
  213.     lsocket.port = udp.dest;
  214.     /* See if there's somebody around to read it */
  215.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  216.         /* Nope, toss it on the floor */
  217.         udp_stat.unknown++;
  218.         free_p(bp);
  219.         return;
  220.     }
  221.     /* Create space for the foreign socket info */
  222.     if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  223.         /* No space, drop whole packet */
  224.         free_p(bp);
  225.         return;
  226.     }
  227.     fsocket = (struct socket *)packet->data;
  228.     fsocket->address = source;
  229.     fsocket->port = udp.source;
  230.  
  231.     /* Queue it */
  232.     enqueue(&up->rcvq,packet);
  233.     up->rcvcnt++;
  234.     if(up->r_upcall)
  235.         (*up->r_upcall)(&lsocket,up->rcvcnt);
  236. }
  237. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  238. static
  239. struct udp_cb *
  240. lookup_udp(socket)
  241. struct socket *socket;
  242. {
  243.     register struct udp_cb *up;
  244.     int16 hash_udp();
  245.  
  246.     up = udps[hash_udp(socket)];
  247.     while(up != NULLUDP){
  248.         if(memcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  249.             break;
  250.         up = up->next;
  251.     }
  252.     return up;
  253. }
  254.  
  255. /* Hash a UDP socket (address and port) structure */
  256. static
  257. int16
  258. hash_udp(socket)
  259. struct socket *socket;
  260. {
  261.     int16 hval;
  262.  
  263.     /* Compute hash function on socket structure */
  264.     hval = hiword(socket->address);
  265.     hval ^= loword(socket->address);
  266.     hval ^= socket->port;
  267.     hval %= NUDP;
  268.     return hval;
  269. }
  270. /* Convert UDP header in internal format to an mbuf in external format */
  271. struct mbuf *
  272. htonudp(udp,data,ph)
  273. struct udp *udp;
  274. struct mbuf *data;
  275. struct pseudo_header *ph;
  276. {
  277.     struct mbuf *bp;
  278.     register char *cp;
  279.     int16 checksum;
  280.  
  281.     /* Allocate UDP protocol header and fill it in */
  282.     if((bp = pushdown(data,UDPHDR)) == NULLBUF)
  283.         return NULLBUF;
  284.  
  285.     cp = bp->data;
  286.     cp = put16(cp,udp->source);    /* Source port */
  287.     cp = put16(cp,udp->dest);    /* Destination port */
  288.     cp = put16(cp,udp->length);    /* Length */
  289.     *cp++ = 0;            /* Clear checksum */
  290.     *cp-- = 0;
  291.  
  292.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  293.      * the spec requires us to change zeros into ones to distinguish an
  294.       * all-zero checksum from no checksum at all
  295.      */
  296.     if((checksum = cksum(ph,bp,ph->length)) == 0)
  297.         checksum = 0xffffffff;
  298.     put16(cp,checksum);
  299.     return bp;
  300. }
  301. /* Convert UDP header in mbuf to internal structure */
  302. ntohudp(udp,bpp)
  303. struct udp *udp;
  304. struct mbuf **bpp;
  305. {
  306.     udp->source = pull16(bpp);
  307.     udp->dest = pull16(bpp);
  308.     udp->length = pull16(bpp);
  309.     udp->checksum = pull16(bpp);
  310. }
  311.